home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
nntplib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
21KB
|
1,019 lines
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdarg.h>
#include <slang.h>
#include "jdmacros.h"
#include "sltcp.h"
#include "nntpcodes.h"
#include "nntplib.h"
#include "util.h"
#include "ttymsg.h"
void (*NNTP_Connection_Lost_Hook) (NNTP_Type *);
int (*NNTP_Authorization_Hook) (char *, char **, char **);
FILE *NNTP_Debug_Fp;
static int _nntp_connect_server (NNTP_Type *);
static NNTP_Type *nntp_allocate_nntp (void)
{
static NNTP_Type nn;
NNTP_Type *s;
s = &nn;
memset ((char *) s, 0, sizeof (NNTP_Type));
s->can_xover = -1;
s->can_xhdr = -1;
s->can_xpat = -1;
s->can_xgtitle = -1;
return s;
}
static void _nntp_deallocate_nntp (NNTP_Type *s)
{
if (s == NULL) return;
memset ((char *) s, 0, sizeof (NNTP_Type));
}
int nntp_fgets_server (NNTP_Type *s, char *buf, unsigned int len)
{
if ((s == NULL) || (s->init_state <= 0))
return -1;
*buf = 0;
if (-1 == sltcp_fgets (s->tcp, buf, len))
{
(void) nntp_disconnect_server (s);
return -1;
}
if (NNTP_Debug_Fp != NULL)
fprintf (NNTP_Debug_Fp, "<%s", buf);
return 0;
}
int nntp_fputs_server (NNTP_Type *s, char *buf)
{
if ((s == NULL) || (s->init_state == 0))
return -1;
if (NNTP_Debug_Fp != NULL)
fprintf (NNTP_Debug_Fp, ">%s\n", buf);
if (-1 == sltcp_fputs (s->tcp, buf))
{
(void) nntp_disconnect_server (s);
return -1;
}
return 0;
}
int nntp_write_server (NNTP_Type *s, char *buf, unsigned int n)
{
if ((s == NULL) || (s->init_state == 0))
return -1;
if (NNTP_Debug_Fp != NULL)
{
unsigned int i;
fputc ('>', NNTP_Debug_Fp);
for (i = 0; i < n; i++)
fputc (buf[i], NNTP_Debug_Fp);
fputc ('\n', NNTP_Debug_Fp);
}
if (n != sltcp_write (s->tcp, buf, n))
{
(void) nntp_disconnect_server (s);
return -1;
}
return 0;
}
int nntp_gets_server (NNTP_Type *s, char *buf, unsigned int len)
{
if (-1 == nntp_fgets_server (s, buf, len))
return -1;
len = strlen (buf);
if (len && (buf[len - 1] == '\n'))
{
len--;
buf[len] = 0;
if (len && (buf[len - 1] == '\r'))
buf[len - 1] = 0;
}
return 0;
}
int nntp_puts_server (NNTP_Type *s, char *buf)
{
if ((-1 == nntp_fputs_server (s, buf))
|| (-1 == nntp_fputs_server (s, "\r\n"))
|| (-1 == sltcp_flush_output (s->tcp)))
{
nntp_disconnect_server (s);
return -1;
}
return 0;
}
static void _nntp_error_response (NNTP_Type *s, char *fmt)
{
slrn_error ("%s", fmt);
slrn_error ("Reason: %s", s->rspbuf);
}
static int _nntp_try_parse_timeout (char *str)
{
/* I know of only two timeout responses:
* 503 Timeout
* 503 connection timed out
*
* Here the idea is to look for 'time' and then 'out'.
*/
static SLRegexp_Type re;
unsigned char compiled_pattern_buf[256];
re.pat = (unsigned char *) "time.*out";
re.buf = compiled_pattern_buf;
re.case_sensitive = 0;
re.buf_len = sizeof (compiled_pattern_buf);
(void) SLang_regexp_compile (&re);
if (NULL == SLang_regexp_match ((unsigned char *) str, strlen (str), &re))
return -1;
return 0;
}
int nntp_get_server_response (NNTP_Type *s)
{
int status;
if ((s == NULL) || (s->init_state <= 0))
return -1;
if (-1 == nntp_gets_server (s, s->rspbuf, NNTP_RSPBUF_SIZE))
return -1;
status = atoi (s->rspbuf);
if (((status == ERR_FAULT) && (-1 != _nntp_try_parse_timeout (s->rspbuf)))
|| (status == ERR_GOODBYE))
{
nntp_disconnect_server (s);
status = -1;
}
s->code = status;
return status;
}
static int _nntp_reconnect (NNTP_Type *s)
{
nntp_disconnect_server (s);
if (0 == (s->flags & NNTP_RECONNECT_OK))
{
if (NNTP_Connection_Lost_Hook != NULL)
(*NNTP_Connection_Lost_Hook) (s);
return -1;
}
s->flags &= ~NNTP_RECONNECT_OK;
slrn_message_now ("Server %s dropped connection. Reconnecting...", s->host);
if (-1 == _nntp_connect_server (s))
{
if (NNTP_Connection_Lost_Hook != NULL)
(*NNTP_Connection_Lost_Hook) (s);
s->flags |= NNTP_RECONNECT_OK;
return -1;
}
if ((s->group_name[0] != 0)
&& (-1 == nntp_server_vcmd (s, "GROUP %s", s->group_name)))
{
if (NNTP_Connection_Lost_Hook != NULL)
(*NNTP_Connection_Lost_Hook) (s);
s->flags |= NNTP_RECONNECT_OK;
return -1;
}
s->flags |= NNTP_RECONNECT_OK;
return 0;
}
int nntp_start_server_cmd (NNTP_Type *s, char *cmd)
{
int max_tries = 3;
if (s == NULL)
return -1;
while ((s->init_state != 0) && max_tries
&& (SLKeyBoard_Quit == 0))
{
if (-1 != nntp_puts_server (s, cmd))
return 0;
if (-1 == _nntp_reconnect (s))
return -1;
max_tries--;
}
return -1;
}
int nntp_server_cmd (NNTP_Type *s, char *cmd)
{
int max_tries = 3;
do
{
int code;
if (-1 == nntp_start_server_cmd (s, cmd))
return -1;
if (-1 != (code = nntp_get_server_response (s)))
return code;
max_tries--;
}
while (max_tries && (s->flags & NNTP_RECONNECT_OK));
return -1;
}
int nntp_server_vcmd (NNTP_Type *s, char *fmt, ...)
{
char buf [NNTP_MAX_CMD_LEN];
va_list ap;
va_start (ap, fmt);
vsprintf (buf, fmt, ap);
va_end (ap);
return nntp_server_cmd (s, buf);
}
int nntp_start_server_vcmd (NNTP_Type *s, char *fmt, ...)
{
char buf [NNTP_MAX_CMD_LEN];
va_list ap;
va_start (ap, fmt);
vsprintf (buf, fmt, ap);
va_end (ap);
return nntp_start_server_cmd (s, buf);
}
int nntp_close_server (NNTP_Type *s)
{
if (s == NULL)
return -1;
if (s->init_state <= 0)
return 0;
s->init_state = -1; /* closing */
/* This might be called from a connect_lost hook. We also do not
* want to reconnect to send the QUIT command so do not call any
* of the *server_cmd functions.
*/
(void) nntp_puts_server (s, "QUIT");
(void) sltcp_close (s->tcp);
s->tcp = NULL;
s->init_state = 0;
_nntp_deallocate_nntp (s);
return 0;
}
static int _nntp_authorization (NNTP_Type *s)
{
char *name, *pass;
if (NNTP_Authorization_Hook == NULL)
return 0;
if (-1 == (*NNTP_Authorization_Hook) (s->host, &name, &pass))
return -1;
if ((name == NULL) || (pass == NULL))
return 0;
slrn_message_now ("Authenticating %s ...", name);
if (-1 == nntp_server_vcmd (s, "AUTHINFO USER %s", name))
return -1;
if (s->code != NEED_AUTHDATA)
return 0;
switch (nntp_server_vcmd (s, "AUTHINFO PASS %s", pass))
{
case -1:
return -1;
case ERR_ACCESS:
_nntp_error_response (s, "Authorization failed.");
return -1;
case OK_AUTH:
s->can_post = 1;
break;
}
return 0;
}
static int _nntp_connect_server (NNTP_Type *s)
{
if (s->tcp != NULL)
sltcp_close (s->tcp);
slrn_message_now ("Connecting to host %s ...", s->host);
if (NULL == (s->tcp = sltcp_open_connection (s->host, s->port)))
return -1;
s->init_state = 1;
/* Read logon message. */
switch (nntp_get_server_response (s))
{
case OK_CANPOST:
s->can_post = 1;
break;
case OK_NOPOST:
s->can_post = 0;
break;
default:
goto failed;
}
if ((-1 == nntp_server_cmd (s, "MODE READER"))
|| (ERR_ACCESS == s->code)
|| (-1 == _nntp_authorization (s)))
goto failed;